#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#include<arpa/inet.h>
#include<sys/socket.h>

#include"ospfpack.h"

unsigned char a2x(const char c){
        switch(c){
                case '0'...'9':
                        return (unsigned char)atoi(&c);
                case 'a'...'f':
                        return 0xa+(c-'a');
                case 'A'...'F':
                        return 0xa+(c-'A');
                default:
                        return c;
        }
        return c;
}

void cpymac(unsigned char *mac,unsigned char*str){
        for(int i=0;i<6;i++){
                mac[i] = (a2x(str[3*i])<<4)+(a2x(str[3*i+1]));
        }
}



extern int ip_cksum(void *data, int len){
        int nleft = len;
        uint16_t *data_tmp = (uint16_t *)data;
        int sum = 0;
        uint16_t tmp = 0;
        while(nleft > 1){
                sum += *data_tmp++;
                nleft -= 2;
        }
        if(nleft == 1){
                *(uint8_t *)(&tmp) = *(uint8_t *)data_tmp;
                sum += tmp;
        }
        sum = (sum >> 16) + (sum &0xffff);
        sum += (sum >> 16);
        tmp = ~sum;
        return tmp;
}


#define ETH_DMAC 101
#define ETH_SMAC 102
#define ETH_TYPE 103
#define IP_LEN 201
#define IP_ID 202
#define IP_FLAGS 204
#define IP_TL 205
#define IP_TYPE 206
#define IP_CKSUM 207
#define IP_SIP 208
#define IP_DIP 209
#define OHEA_TYPE 301
#define OHEA_LEN 302
#define OHEA_RID 303
#define OHEA_AID 304
#define OHEA_CKSUM 305
#define OHEL_MASK 401
#define OHEL_HEL_INT 402
#define OHEL_DED_INT 403
#define OHEL_FALGS 404
#define OHEL_DR 405
#define OHEL_BDR 406

void setattr(void *packet,int flag,void *attr){
	int offest=-1,len=-1;
	int e=0;
	int p=sizeof(eth);
	int ospf=sizeof(eth)+sizeof(ip);
	int oth=ospf+sizeof(ospfhel);
	switch(flag){
		case ETH_DMAC:{offest=e+0;len=6;break;}
		case ETH_SMAC:{offest=e+6;len=6;break;}
		case ETH_TYPE:{offest=e+12;len=2;break;}
		case IP_LEN:{offest=p+2;len=2;break;}
		case IP_ID:{offest=p+4;len=2;break;}
		case IP_FLAGS:{offest=p+6;len=1;break;}
		case IP_TL:{offest=p+8;len=1;break;}
		case IP_TYPE:{offest=p+9;len=1;break;}
		case IP_CKSUM:{offest=p+10;len=2;break;} 
		case IP_SIP:{offest=p+12;len=4;break;}
		case IP_DIP:{offest=p+16;len=4;break;}
		case OHEA_TYPE:{offest=ospf+1;len=1;break;}
		case OHEA_LEN:{offest=ospf+2;len=2;break;}
		case OHEA_RID:{offest=ospf+4;len=4;break;}
		case OHEA_AID:{offest=ospf+8;len=4;break;}
		case OHEA_CKSUM:{offest=ospf+12;len=4;break;}
		case OHEL_MASK:{offest=oth;len=4;break;}
		case OHEL_HEL_INT:{offest=oth+4;len=2;break;}
		case OHEL_DED_INT:{offest=oth+8;len=4;break;}
		case OHEL_FALGS:{offest=oth+6;len=1;break;}
		case OHEL_DR:{offest=oth+12;len=4;break;}
		case OHEL_BDR:{offest=oth+16;len=4;break;}
	}
	if(offest==-1||len==-1){
		printf("attr error\n");
		return;
	}
	memcpy(packet+offest,attr,len);
	return;
}


void getattr(void *packet,int flag,void *attr){
        int offest=-1,len=-1;
        int e=0;
        int p=sizeof(eth);
        int ospf=sizeof(eth)+sizeof(ip);
	int oth=ospf+sizeof(ospfhea);
        switch(flag){
                case ETH_DMAC:{offest=e+0;len=6;break;}
                case ETH_SMAC:{offest=e+6;len=6;break;}
                case ETH_TYPE:{offest=e+12;len=2;break;}
                case IP_LEN:{offest=p+2;len=2;break;}
                case IP_ID:{offest=p+4;len=2;break;}
                case IP_FLAGS:{offest=p+6;len=1;break;}
                case IP_TL:{offest=p+8;len=1;break;}
                case IP_TYPE:{offest=p+9;len=1;break;}
                case IP_CKSUM:{offest=p+10;len=2;break;}
                case IP_SIP:{offest=p+12;len=4;break;}
                case IP_DIP:{offest=p+16;len=4;break;}
                case OHEA_TYPE:{offest=ospf+1;len=1;break;}
                case OHEA_LEN:{offest=ospf+2;len=2;break;}
                case OHEA_RID:{offest=ospf+4;len=4;break;}
                case OHEA_AID:{offest=ospf+8;len=4;break;}
                case OHEA_CKSUM:{offest=ospf+12;len=4;break;}
		case OHEL_MASK:{offest=oth;len=4;break;}
                case OHEL_HEL_INT:{offest=oth+4;len=2;break;}
                case OHEL_DED_INT:{offest=oth+8;len=4;break;}
                case OHEL_FALGS:{offest=oth+6;len=1;break;}
                case OHEL_DR:{offest=oth+12;len=4;break;}
                case OHEL_BDR:{offest=oth+16;len=4;break;}
        }
        if(offest==-1||len==-1){
                printf("attr error\n");
                return;
        }
        memcpy(attr,packet+offest,len);
        return;
}

